package com.dingceng.demo.swipecard.view;

import android.animation.ValueAnimator;
import android.content.Context;
import android.graphics.Outline;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewOutlineProvider;
import android.view.animation.DecelerateInterpolator;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.Toast;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;


import com.dingceng.demo.photo.R;
import com.dingceng.demo.swipecard.bean.CardPlace;
import com.dingceng.demo.swipecard.bean.Data;
import com.dingceng.demo.swipecard.interfaces.OnSwipeCardChange;

import java.util.ArrayList;
import java.util.List;

public class SwipeCardView extends FrameLayout {
    
    List<CardPlace> cardPlaces;
    List<Data> dataList;
    OnSwipeCardChange onSwipeCardChange;
    
    public SwipeCardView(@NonNull Context context) {
        super(context);
        init();
    }
    
    public SwipeCardView(@NonNull Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        init();
    }
    
    public SwipeCardView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init();
    }
    
    public SwipeCardView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
        init();
    }
    
    boolean isInit;
    
    void init() {
        if (!isInit) {
            //预准备各卡片的角度和位置
            cardPlaces = new ArrayList<>();
            cardPlaces.add(new CardPlace(dip2px(-100), -dip2px(130), -30));
            cardPlaces.add(new CardPlace(dip2px(-50), -dip2px(100), -15));
            cardPlaces.add(new CardPlace(0, 0, 0));
            cardPlaces.add(new CardPlace(dip2px(-50), dip2px(100), 15));
            cardPlaces.add(new CardPlace(dip2px(-100), dip2px(130), 30));
            isInit = true;
        }
    }
    
    public void setDataList(List<Data> dataList) {
        this.dataList = new ArrayList<>(dataList);
        isNextCardFlag = false;
        post(new Runnable() {
            @Override
            public void run() {
                initViews();
            }
        });
    }
    
    public void loadMoreDataList(List<Data> dataList) {
        isNextCardFlag = false;
        this.dataList.addAll(dataList);
        if (touchMoveScale!=1f) {
            nextAnimation();
        }else{
            this.dataList.remove(0);
            initViews();
        }
    }
    
    /**
     * dp 转 px
     *
     * @param dpValue dp值
     * @return px值
     */
    public int dip2px(float dpValue) {
        float scale = getResources().getDisplayMetrics().density;
        return (int) (dpValue * scale + 0.5f);
    }
    
    float touchMoveScale;
    
    /**
     * 回弹动画
     */
    private void backAnimation() {
        ValueAnimator valueAnimator = ValueAnimator.ofFloat(touchMoveScale, 0f);
        valueAnimator.setDuration(300);
        valueAnimator.setInterpolator(new DecelerateInterpolator(2f));
        valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                float scale = (float) animation.getAnimatedValue();
                refreshViewPlace(scale);
            }
        });
        valueAnimator.start();
    }
    
    /**
     * 下一个动画
     */
    private void nextAnimation() {
        ValueAnimator valueAnimator = ValueAnimator.ofFloat(touchMoveScale, 1f);
        valueAnimator.setDuration(300);
        valueAnimator.setInterpolator(new DecelerateInterpolator(2f));
        valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                float scale = (float) animation.getAnimatedValue();
                if (scale != 1f) {
                    refreshViewPlace(scale);
                } else {
                    refreshViewPlace(0);
                    nextCard();
                }
            }
        });
        valueAnimator.start();
    }
    
    //是否为“下一个”标记，在软件启动加载时，此标记为 false，用于判断是否显示最后一个卡片的切入动画
    private boolean isNextCardFlag;
    
    /**
     * 切换到下一个卡片指令
     */
    private void nextCard() {
        if (!dataList.isEmpty()) dataList.remove(0);
        isNextCardFlag = true;
        initViews();
    }
    
    //所有卡片布局
    private List<ImageView> cardViews;
    
    /**
     * 初始化所有卡片布局（5 个）
     */
    private void initViews() {
        cardViews = new ArrayList<>();
        cardViews.add(newCardImageView());
        cardViews.add(newCardImageView());
        cardViews.add(newCardImageView());
        cardViews.add(newCardImageView());
        cardViews.add(newCardImageView());
        //添加至界面上
        removeAllViews();
        for (ImageView cardView : cardViews) {
            addView(cardView);
        }
        //根据 cardPlaces 刷新各卡片位置
        refreshViewPlace();
    }
    
    /**
     * 根据 cardPlaces 刷新各卡片位置
     */
    private void refreshViewPlace() {
        //最大卡片数量，不得多于 5 个
        int maxCardView;
        for (int i = 0; i < (maxCardView = Math.min(cardViews.size(), 5)); i++) {
            ImageView cardView = cardViews.get(i);
            CardPlace cardPlace = cardPlaces.get(i);
            if (i == maxCardView - 1 && isNextCardFlag) {
                //若是最后一个卡片且有“下一个”标记，显示最后一个卡片的切入动画，先初始为全透明，倾斜 45 度，逐渐不透明，回到正常倾斜角度
                cardView.setAlpha(0f);
                cardView.setRotation(45);
                //开始动画
                cardView.animate().rotation(cardPlace.getRotation()).alpha(1f);
            } else {
                //其他卡片直接切换到对应角度
                cardView.setRotation(cardPlace.getRotation());
            }
            //设置其位置 x、y（boxRoot 高度一半 ± 预设位置的差值 - 卡片高度的一半（200dp / 2 = 100dp））
            cardView.setX(cardPlace.getX());
            cardView.setY(getHeight() / 2 - dip2px(100) + cardPlace.getY());
        }
        //设置 1、3 卡片置顶
        cardViews.get(1).bringToFront();
        cardViews.get(3).bringToFront();
        //设置最中央的 2 卡片置顶
        cardViews.get(2).bringToFront();
        
        for (int i = 0; i < Math.min(dataList.size(), 3); i++) {
            if (i < cardViews.size()) {
                //设置背景图
                cardViews.get(i).setImageResource(dataList.get(i).getImageResId());
            }
        }
        
        getOnSwipeCardChange().onChange(dataList.get(Math.min(dataList.size() - 1, 2)));
    }
    
    /**
     * 根据滑动比例刷新各卡片位置
     *
     * @param scale 比例值（0.0~1.0 浮点）
     */
    private void refreshViewPlace(float scale) {
        for (int i = 0; i < Math.min(cardViews.size(), 5); i++) {
            ImageView cardView = cardViews.get(i);
            
            if (i == 0) {
                //第一张卡片，只逐渐透明
                cardView.setAlpha(1f - scale);
            } else if (i == 2) {
                CardPlace lastCardPlace = cardPlaces.get(i - 1);        //获取上一张卡片的固定预设位置
                CardPlace cardPlace = cardPlaces.get(i);                //获得当前卡片预设位置
                
                //中央的卡片，又一个向右倾斜的偏移值，影响 x 坐标位移以及角度变化
                float offsetX = 1f - Math.abs(0.5f - scale) * 2f;   //计算偏移量，从 scale = 0.0~1.0 时获得值 [0.0 ~ 1.0 ~ 0.0]
                
                //角度的倾斜过程，额外加偏移值 * 10
                float transitionRotation = cardPlace.getRotation() + (lastCardPlace.getRotation() - cardPlace.getRotation()) * scale + 10 * offsetX;
                cardView.setRotation(transitionRotation);
                
                //x 坐标的微移过程，额外加偏移值 * 20dp
                int transitionX = (int) ((cardPlace.getX() + (lastCardPlace.getX() - cardPlace.getX()) * scale) + (dip2px(20) * offsetX));
                cardView.setX(transitionX);
                
                int transitionY = (int) (cardPlace.getY() + (lastCardPlace.getY() - cardPlace.getY()) * scale);
                cardView.setY(getHeight() / 2 - dip2px(100) + transitionY);
            } else {
                CardPlace lastCardPlace = cardPlaces.get(i - 1);        //获取上一张卡片的固定预设位置
                CardPlace cardPlace = cardPlaces.get(i);                //获得当前卡片预设位置
                
                //其他卡片，逐渐向自己的目标（赏一张卡片）的固定位置移动
                float transitionRotation = cardPlace.getRotation() + (lastCardPlace.getRotation() - cardPlace.getRotation()) * scale;
                cardView.setRotation(transitionRotation);
                
                int transitionX = (int) (cardPlace.getX() + (lastCardPlace.getX() - cardPlace.getX()) * scale);
                cardView.setX(transitionX);
                
                int transitionY = (int) (cardPlace.getY() + (lastCardPlace.getY() - cardPlace.getY()) * scale);
                cardView.setY(getHeight() / 2 - dip2px(100) + transitionY);
            }
        }
    }
    
    /**
     * 创建新卡片 View
     *
     * @return 卡片 View
     */
    private ImageView newCardImageView() {
        ImageView imageView = new ImageView(getContext());
        LayoutParams lp = new LayoutParams(dip2px(200), dip2px(200));
        imageView.setLayoutParams(lp);
        imageView.setOutlineProvider(new ViewOutlineProvider() {
            @Override
            public void getOutline(View view, Outline outline) {
                outline.setRoundRect(0, 0, view.getWidth(), view.getHeight(), dip2px(10));
            }
        });
        imageView.setClipToOutline(true);
        imageView.setBackgroundResource(R.mipmap.img_music_default);
        return imageView;
    }
    
    
    //触摸按下标记
    boolean touchDown = false;
    //记录按下时触摸 Y 坐标
    float touchY;
    
    @Override
    public boolean onTouchEvent(MotionEvent event) {
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:   //按下时
                touchDown = true;
                touchY = event.getY();
                break;
            case MotionEvent.ACTION_MOVE:   //触摸滑动
                if (touchDown) {
                    float deltaY = event.getY() - touchY;       //计算滑动距离
                    float scale = deltaY > 0 ? 0 : Math.abs(deltaY / dip2px(200));  //按最大滑动距离 200dp 计算已滑动的比例（0.0~1.0 浮点）
                    if (scale < 0) scale = 0;       //不可越界
                    if (scale > 1) scale = 1;
                    touchMoveScale = scale;         //记录滑动比例
                    refreshViewPlace(scale);        //按照滑动比例刷新各卡片布局位置
                }
                break;
            case MotionEvent.ACTION_UP:
            case MotionEvent.ACTION_CANCEL: //松开时
                touchDown = false;
                if (dataList.size() > 3) {
                    //若还有三个以上剩余的数据
                    if (touchMoveScale == 1f) {     //已经滑动到最大滑动距离的顶点
                        refreshViewPlace(0);    //回到滑动起点
                        nextCard();                 //删掉顶部数据，并刷新卡片界面
                    } else if (touchMoveScale != 0f) {
                        nextAnimation();            //播放“下一个”动画
                    }
                } else {
                    if (getOnSwipeCardChange().onLoadMore()){
                    
                    }else{
                        //没有更多的卡片了
                        Toast.makeText(getContext(), "已经没有新的歌曲", Toast.LENGTH_SHORT).show();
                        //回弹动画
                        backAnimation();
                    }
                }
                break;
        }
        return true;
    }
    
    public OnSwipeCardChange getOnSwipeCardChange() {
        return onSwipeCardChange == null ? new OnSwipeCardChange() {
            @Override
            public void onChange(Data data) {
                //空实现
            }
    
            @Override
            public boolean onLoadMore() {
                return false;
            }
        } : onSwipeCardChange;
    }
    
    public SwipeCardView setOnSwipeCardChange(OnSwipeCardChange onSwipeCardChange) {
        this.onSwipeCardChange = onSwipeCardChange;
        return this;
    }
}
